﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using Microsoft.Office.Project.Server.Library;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using System.Globalization;

namespace Microsoft.Office.Project.EPMAuditing.Library
{
    public class AuditEvent : IDisposable
    {
        private ChangeRecord _change;
        private UdpClient _client;
        private IPEndPoint _endPoint;
        
        private EPMAuditingConfigFile _configFile;
        private EPMAuditingConfig _config;

        #region Constructor/Destructor

        public AuditEvent() : this(DateTime.Now, string.Empty, string.Empty, null, null, null) { }

        public AuditEvent(DateTime eventTime, string eventSourceName, string eventName,
                          PSContextInfo eventContextInfo, object projectServerEventArgs)
            : this(eventTime, eventSourceName, eventName, eventContextInfo, projectServerEventArgs, null) { }


        public AuditEvent(DateTime eventTime, string eventSourceName, string eventName,
                          PSContextInfo eventContextInfo, object projectServerEventArgs, string dataSetChanges)
        {
            if (dataSetChanges != null)
                _change = new ChangeRecord(eventTime, eventSourceName, eventName, eventContextInfo, projectServerEventArgs, dataSetChanges);
            else if (eventContextInfo != null)
                _change = new ChangeRecord(eventTime, eventSourceName, eventName, eventContextInfo, projectServerEventArgs);
            else
                _change = new ChangeRecord();

            InitializeData();
            AddNetAuditing();
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _client.Close();
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(true);
        }

        private void InitializeData()
        {
            // Read configuration file
            string fullPath = Assembly.GetExecutingAssembly().Location;
            _configFile = new EPMAuditingConfigFile(string.Format(CultureInfo.InvariantCulture, "{0}{1}", 
                fullPath.Substring(0, fullPath.LastIndexOf(@"\", StringComparison.OrdinalIgnoreCase) + 1), 
                EPMAuditingConfigFile.DEFAULT_CONFIG_FILENAME), true);
            _config = _configFile.AuditingConfiguration;
        }

        #endregion

        #region Properties
        public DateTime EventTime
        {
            get
            {
                return _change.EventTime;
            }
            set
            {
                _change.EventTime = value;
            }
        }

        public PSContextInfo EventContextInfo
        {
            get
            {
                return _change.EventContextInfo;
            }
            set
            {
                _change.EventContextInfo = value;
            }
        }

        public string EventName
        {
            get
            {
                return _change.EventName;
            }
            set
            {
                _change.EventName = value;
            }
        }

        public string EventSourceName
        {
            get
            {
                return _change.EventSourceName;
            }
            set
            {
                _change.EventSourceName = value;
            }
        }

        public string DataSetChanges
        {
            get
            {
                return _change.DataSetChanges;
            }
            set
            {
                _change.DataSetChanges = value;
            }
        }


        #endregion

        #region Transport
        private void AddNetAuditing()
        {
            _endPoint = new IPEndPoint(IPAddress.Parse(_config.NetAuditingServerIP), _config.NetAuditingServerPort);
            _client = new UdpClient();
        }

        public void Post()
        {
            try
            {
                if (!_change.RecordComplete)
                    throw (new ArgumentNullException("ChangeRecord", "The change record must be completely initialized before posting the event."));

                if (_client != null)
                {
                    MessageSegmentCollection ms = new MessageSegmentCollection(_change.ToMemoryStream());
                    foreach (MessageSegment mseg in ms)
                    {
                        Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Write to UDP UID: {0}, {1} of {2}", 
                            mseg.MessageUid.ToString(), mseg.SegmentNumber.ToString(), mseg.SegmentCount.ToString()));
                        byte[] bytes = mseg.ToArray();
                        _client.Send(bytes, bytes.Length, _endPoint);
                    }

                }
            }
            catch (ArgumentNullException ex)
            {
                Debug.WriteLine("Post Audit Event, ProcessingState Null");
                throw (new Exception("Post Audit Event, ProcessingState Null", ex));
            }
            catch (EncoderFallbackException ex)
            {
                Debug.WriteLine("Post Audit Event, Encoder Fallback");
                throw (new Exception("Post Audit Event, Encoder Fallback", ex));
            }
            catch (ObjectDisposedException ex)
            {
                Debug.WriteLine("Post Audit Event, UDP client was already closed");
                throw (new Exception("Post Audit Event, UDP client was already closed", ex));
            }
            catch (InvalidOperationException ex)
            {
                Debug.WriteLine("Post Audit Event, Invalid Operation on UPD Send");
                throw (new Exception("Post Audit Event, Invalid Operation on UPD Send", ex));
            }
            catch (SocketException ex)
            {
                Debug.WriteLine("Post Audit Event, Socket Error");
                throw (new Exception("Post Audit Event, Socket Error", ex));
            }
        }

        #endregion

        #region Source and Event Name Manipulation

        //public const string AdminSource = "Admin";
        //public const string CalendarSource = "Calendar";
        //public const string CubeAdminSource = "CubeAdmin";
        //public const string CustomFieldsSource = "CustomFields";
        //public const string LookupTableSource = "LookupTable";
        //public const string NotificationsSource = "Notifications";
        //public const string ProjectSource = "Project";
        //public const string ReportingSource = "Reporting";
        //public const string ResourceSource = "Resource";
        //public const string RulesSource = "Rules";
        //public const string SecuritySource = "Security";
        //public const string StatusingSource = "Statusing";
        //public const string StatusReportsSource = "StatusReports";
        //public const string TimesheetSource = "Timesheet";
        //public const string WssInteropSource = "WssInterop";

        //private static string[] SourceNames = {  AdminSource,
        //                                        CalendarSource,
        //                                        CubeAdminSource,
        //                                        CustomFieldsSource,
        //                                        LookupTableSource,
        //                                        NotificationsSource,
        //                                        ProjectSource,
        //                                        ReportingSource,
        //                                        ResourceSource,
        //                                        RulesSource,
        //                                        SecuritySource,
        //                                        StatusingSource,
        //                                        StatusReportsSource,
        //                                        TimesheetSource,
        //                                        WssInteropSource };

        //private static bool IsSourceNameValid(string sourceNameCheck)
        //{
        //    foreach (string sourceName in SourceNames)
        //    {
        //        if (sourceNameCheck == sourceName)
        //            return true;
        //    }
        //    return false;
        //}

        //private bool IsEventNameValid(string eventName)
        //{
        //    switch (EventSourceName)
        //    {
        //        case AdminSource:
        //            switch (eventName)
        //            {
        //                case "OnAdSyncERPSynchronized":
        //                case "OnAdSyncERPSynchronizing":
        //                case "OnAdSyncGroupsSynchronized":
        //                case "OnAdSyncGroupsSynchronizing":
        //                case "OnAdSyncGroupSynchronized":
        //                case "OnAdSyncGroupSynchronizing":
        //                case "OnLineClassUpdated":
        //                case "OnLineClassUpdating":
        //                case "OnReportingPeriodUpdated":
        //                case "OnReportingPeriodUpdating":
        //                case "OnStatusReportsDeleted":
        //                case "OnStatusReportsDeleting":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case CalendarSource:
        //            switch (eventName)
        //            {
        //                case "OnChanged":
        //                case "OnChanging":
        //                case "OnCheckedIn":
        //                case "OnCheckedOut":
        //                case "OnCheckingIn":
        //                case "OnCheckingOut":
        //                case "OnCreated":
        //                case "OnCreating":
        //                case "OnDeleted":
        //                case "OnDeleting":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case CubeAdminSource:
        //            switch (eventName)
        //            {
        //                case "OnCubeBuilding":
        //                case "OnCubeBuilt":
        //                case "OnCubeProcessed":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case CustomFieldsSource:
        //            switch (eventName)
        //            {
        //                case "OnCheckedIn":
        //                case "OnCheckedOut":
        //                case "OnCheckingIn":
        //                case "OnCheckingOut":
        //                case "OnCreated":
        //                case "OnCreating":
        //                case "OnDeleted":
        //                case "OnDeleting":
        //                case "OnUpdated":
        //                case "OnUpdating":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case LookupTableSource:
        //            switch (eventName)
        //            {
        //                case "OnCheckedIn":
        //                case "OnCheckedOut":
        //                case "OnCheckingIn":
        //                case "OnCheckingOut":
        //                case "OnCreated":
        //                case "OnCreating":
        //                case "OnDeleted":
        //                case "OnDeleting":
        //                case "OnUpdated":
        //                case "OnUpdating":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case NotificationsSource:
        //            switch (eventName)
        //            {
        //                case "OnSending":
        //                case "OnSent":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case ProjectSource:
        //            switch (eventName)
        //            {
        //                case "OnActivityUpgraded":
        //                case "OnActivityUpgrading":
        //                case "OnAdded":
        //                case "OnAdding":
        //                case "OnCheckIn":
        //                case "OnCreated":
        //                case "OnCreating":
        //                case "OnDeleted":
        //                case "OnDeleting":
        //                case "OnEntitiesDeleted":
        //                case "OnEntitiesDeleting":
        //                case "OnPublished":
        //                case "OnPublishing":
        //                case "OnSaved":
        //                case "OnSaveFailed":
        //                case "OnUpdated":
        //                case "OnUpdating":
        //                case "OnWssWorkspaceAddressDeleted":
        //                case "OnWssWorkspaceAddressDeleting":
        //                case "OnWssWorkspaceAddressUpdated":
        //                case "OnWssWorkspaceAddressUpdating":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case ReportingSource:
        //            switch (eventName)
        //            {
        //                case "OnCustomFieldChanged":
        //                case "OnCustomFieldCreated":
        //                case "OnCustomFieldDeleted":
        //                case "OnFiscalPeriodChanged":
        //                case "OnFiscalPeriodDeleted":
        //                case "OnLookupTableChanged":
        //                case "OnLookupTableCreated":
        //                case "OnLookupTableDeleted":
        //                case "OnProjectChanged":
        //                case "OnProjectCreated":
        //                case "OnProjectDeleted":
        //                case "OnProjectWorkspaceChanged":
        //                case "OnProjectWorkspaceCreated":
        //                case "OnProjectWorkspaceDeleted":
        //                case "OnResourceCapacitiesChanged":
        //                case "OnResourceCapacityTimeRangeChanged":
        //                case "OnResourceChanged":
        //                case "OnResourceCreated":
        //                case "OnResourceDeleted":
        //                case "OnTimesheetAdjusted":
        //                case "OnTimesheetClassChanged":
        //                case "OnTimesheetDeleted":
        //                case "OnTimesheetPeriodChanged":
        //                case "OnTimesheetPeriodCreated":
        //                case "OnTimesheetPeriodDeleted":
        //                case "OnTimesheetSaved":
        //                case "OnTimesheetStatusChanged":
        //                case "OnUserViewChanged":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case ResourceSource:
        //            switch (eventName)
        //            {
        //                case "OnActivated":
        //                case "OnActivating":
        //                case "OnChanged":
        //                case "OnChanging":
        //                case "OnCheckedIn":
        //                case "OnCheckedOut":
        //                case "OnCheckingIn":
        //                case "OnCheckingOut":
        //                case "OnCreated":
        //                case "OnCreating":
        //                case "OnDeactivated":
        //                case "OnDeactivating":
        //                case "OnDeleted":
        //                case "OnDeleting":
        //                case "OnSetAuthorization":
        //                case "OnSettingAuthorization":
        //                    return true;
        //                default:
        //                    return false;
        //            }
        //        case RulesSource:
        //            switch (eventName)
        //            {
        //                case "OnCopied":
        //                case "OnCopying":
        //                case "OnCreated":
        //                case "OnCreating":
        //                case "OnDeleted":
        //                case "OnDeleting":
        //                case "OnProcessed":
        //                case "OnProcessing":
        //                   return true;
        //                default:
        //                    return false;
        //            }

        //        case SecuritySource:
        //            switch (eventName)
        //            {
        //                case "OnCategoryCreated":
        //                case "OnCategoryCreating":
        //                case "OnCategoryDeleted":
        //                case "OnCategoryDeleting":
        //                case "OnCategoryUpdated":
        //                case "OnCategoryUpdating":
        //                case "OnGroupCreated":
        //                case "OnGroupCreating":
        //                case "OnGroupDeleted":
        //                case "OnGroupDeleting":
        //                case "OnGroupUpdated":
        //                case "OnGroupUpdating":
        //                case "OnOrganizationalPermissionsUpdated":
        //                case "OnOrganizationalPermissionsUpdating":
        //                case "OnTemplateCreated":
        //                case "OnTemplateCreating":
        //                case "OnTemplateDeleted":
        //                case "OnTemplateDeleting":
        //                case "OnTemplateUpdated":
        //                case "OnTemplateUpdating":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case StatusingSource:
        //            switch (eventName)
        //            {
        //                case "OnApplied":
        //                case "OnApplying":
        //                case "OnApprovalsUpdated":
        //                case "OnApprovalsUpdating":
        //                case "OnAssignmentDelegated":
        //                case "OnAssignmentDelegating":
        //                case "OnAssignmentDeleted":
        //                case "OnAssignmentDeleting":
        //                case "OnAssignmentWorkDataSet":
        //                case "OnAssignmentWorkDataSetting":
        //                case "OnHistoryDeleted":
        //                case "OnHistoryDeleting":
        //                case "OnStatusSubmiting":
        //                case "OnStatusSubmitted":
        //                case "OnStatusUpdated":
        //                case "OnStatusUpdating":
        //                case "OnTaskCreated":
        //                case "OnTaskCreating":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case StatusReportsSource:
        //            switch (eventName)
        //            {
        //                case "OnRequestCreated":
        //                case "OnRequestCreating":
        //                case "OnRequestUpdated":
        //                case "OnRequestUpdating":
        //                case "OnResponseCreated":
        //                case "OnResponseCreating":
        //                case "OnResponseUpdated":
        //                case "OnResponseUpdating":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case TimesheetSource:
        //            switch (eventName)
        //            {
        //                case "OnCreated":
        //                case "OnCreating":
        //                case "OnDeleted":
        //                case "OnDeleting":
        //                case "OnLineApproved":
        //                case "OnLineApproving":
        //                case "OnRecalled":
        //                case "OnRecalling":
        //                case "OnReviewed":
        //                case "OnReviewing":
        //                case "OnSubmitted":
        //                case "OnSubmitting":
        //                case "OnUpdated":
        //                case "OnUpdating":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        case WssInteropSource:
        //            switch (eventName)
        //            {
        //                case "OnWssWorkspaceCreated":
        //                case "OnWssWorkspaceCreating":
        //                    return true;
        //                default:
        //                    return false;
        //            }

        //        default:
        //            return false;
        //    }

        //}

        #endregion



    }
}
